#include "examples.h"
void Examples::TestPolyMult()
{
    cout<<"   TestPolyMult..."<<endl;
    // 对于函数 f(x) = x^3 + 1.5x^2 + x + 0.5 , 计算x = {1,2,3,4,5}的结果并验证
    // 1. 设置安全参数
    long logN = 16;
    long lambda = 128;
    int dNum = 3;

    // 2.初始化参数相关内容
    // Context context = Context::InitContext(logN);
    // Context context = Context::InitContext(logN, lambda);
    Context context = Context::InitContext(logN, lambda, dNum);

    // 3.计算私钥
    SecretKey secretKey(context);

    // 4.初始化同态操作相关内容
    Scheme scheme(secretKey, context);

    // 5.初始化消息值
    long slots = context.slots;
    complex<double> *mvec = new complex<double>[slots];
    complex<double> *mvecPoly = new complex<double>[slots];
    // 设置前五个值为1,2,3,4,5
    for (int i = 0; i < 5; ++i) {
        mvec[i] = std::complex<double>(i + 1, 0);
    }

    // 6.计算多项式运算结果
    for (long i = 0; i < slots; i++) {
        mvecPoly[i] = pow(mvec[i], 3) + 1.5 * pow(mvec[i], 2) + mvec[i] + 0.5;
    }

    // 7.计算同态运算结果
    Ciphertext cipher = scheme.Encrypt(mvec, slots, context.L);
    Ciphertext multCipher2 = Ciphertext(context.N, slots, context.L, context.p);
    Ciphertext multCipher3 = Ciphertext(context.N, slots, context.L, context.p);
    
    scheme.Mult(multCipher2, cipher, cipher);
    scheme.ReScaleByAndEqual(multCipher2, 1); //multCipher2: x^2
    scheme.Mult(multCipher3, multCipher2, cipher); 
    scheme.ReScaleByAndEqual(multCipher3, 1);//multCipher3: x^3
    scheme.MultByConstAndEqual(multCipher2, 1.5);
    scheme.ReScaleByAndEqual(multCipher2, 1);//multCipher2: 1.5 * x^2
    scheme.AddAndEqual(cipher, multCipher2);//cipher: x + 1.5 * x^2
    scheme.AddAndEqual(cipher, multCipher3);//cipher: x + 1.5 * x^2 + x^3
    scheme.AddConstAndEqual(cipher, 0.5);//cipher: 0.5 + x + 1.5 * x^2 + x^3
    
    // 8.将同态运算结果与正确值进行对比
    complex<double> *dvecMult = scheme.Decrypt(secretKey, cipher);
    StringUtils::ShowCompare(mvecPoly, dvecMult, 5, "PolyMult");
}


void Examples::TestRotate()
{   
    cout<<"   TestRotate..."<<endl;
    // 设置满槽消息 , 进行同态旋转并验证结果
    // 1. 设置安全参数
    long logN = 15;
    long lambda = 128;
    int dNum = 3;
    // 2.初始化参数相关内容
    Context context = Context::InitContext(logN);
    // Context context = Context::InitContext(logN, lambda);
    // Context context = Context::InitContext(logN, lambda, dNum);

    // 3.计算私钥
    SecretKey secretKey(context);

    // 4.设置旋转索引
    int rotSlots = 2;

    // 5.初始化同态操作相关内容
    Scheme scheme(secretKey, context);
    scheme.AddLeftRotKey(secretKey, rotSlots);
    
    
    // 6.设置消息值
    long slots = context.N / 2;
    complex<double> *mvec = new complex<double>[slots];
    for (int i = 0; i < slots; i++) {
        double num = (i % 100) / 100.0;
        mvec[i].real(num);
        mvec[i].imag(num);
    }

    // 7.加密消息值
    Ciphertext cipher = scheme.Encrypt(mvec, slots, context.L);
    // 8.进行同态旋转操作并解密结果
    scheme.LeftRotateAndEqual(cipher, rotSlots);
    complex<double> *dvec = scheme.Decrypt(secretKey, cipher);
    
    // 9.对消息值进行旋转并与解密结果对比
    EvaluatorUtils::LeftRotateAndEqual(mvec, slots, rotSlots);
    StringUtils::ShowCompare(mvec, dvec, 10, "rot");
}


void Examples::TestBootStrapping()
{
    cout<<"   TestBootStrapping..."<<endl;
    // 1. 设置多项式次数
    long logN = 12;

    // 2.初始化参数相关内容
    Context context = Context::InitContextBootStrapping(logN);
    
    // 3.计算私钥
    SecretKey secretKey(context);

    // 4.初始化同态操作相关参数
    Scheme scheme(secretKey, context);
    scheme.AddConjKey(secretKey);
    
    // 5.初始化自举操作相关参数
    EvalModPoly evalModPoly;
    EncodingMatrix encodingMatrix(secretKey, scheme);
    Bootstrapper bootstrapper(context, scheme, secretKey, evalModPoly, encodingMatrix);
    long slots = context.Nh;

    // 6.初始化自举操作预计算矩阵
    

    // 7.设置消息值
    double bound = 1.0;
    complex<double> *mvec1 = EvaluatorUtils::RandomComplexArray(slots, bound);
    complex<double> *mvec2 = EvaluatorUtils::RandomComplexArray(slots, bound);
    complex<double> *mvecMult = new complex<double>[slots];
    complex<double> *mvecMult1 = new complex<double>[slots];

    for (long i = 0; i < slots; i++) {
        mvecMult[i] = mvec1[i] * mvec2[i];
        mvecMult1[i] = mvecMult[i] * mvecMult[i];
    }
    for (int i = 0; i < slots; i++) {
        double ab = double(i % 10);
        mvec1[i].real(ab / 10);
        mvec1[i].imag(0);
    }

    // 8.加密消息值
    Ciphertext cipher = scheme.Encrypt(mvec1, slots, context.L);
    int level = cipher.l - 2;

    // 9.对密文进行乘法 密文层数剩余2层
    for(int i = 0; i < level; i++) {
        scheme.MultByConstAndEqual(cipher, 1);
        scheme.ReScaleByAndEqual(cipher, 1);
    }
    // 10.对密文自举并解密测试
    bootstrapper.BootStrapping(cipher);
    complex<double> *dvecMult2 = scheme.Decrypt(secretKey, cipher);
    StringUtils::ShowCompare(mvec1, dvecMult2, 10, "Bootstrapping");
}
